package mts.groupdispatcher;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import mts.common.CommonSettings;
import mts.messages.StatusMessage;
import mts.strategies.MediaStrategy;

import org.apache.log4j.Logger;

/**
 * @author Nick
 *
 */
public class GroupDispatcher extends TimerTask {
	private static final Logger log = Logger.getLogger(GroupDispatcher.class);
	
	
	private List<FloorRequest> floorRequests = new ArrayList<FloorRequest>(60);
	private HashMap<Byte, ElevatorControllerConnection> elevatorControllers = new HashMap<Byte, ElevatorControllerConnection>(CommonSettings.MAX_ELEVATOR_CONTROLLERS);
	private ProjectController controller;	
	private MediaStrategy mediaStrategy;
	
	public void assignNewHallCallToElevatorController(Byte car, FloorRequest floorRequest) {
		elevatorControllers.get(car).addNewHallCall(floorRequest);
	}
	
	
	public ElevatorControllerConnection getElevatorController(byte car) {
		synchronized(elevatorControllers) {
			return elevatorControllers.get(car);		
		}
	}
	
	public Collection<ElevatorControllerConnection> getElevatorControllers() {
		return elevatorControllers.values();
	}
	
	public StatusMessage getElevatorControllerStatusMessage(byte car) {
		ElevatorControllerConnection controller;
		synchronized(elevatorControllers) {
			controller = elevatorControllers.get(car);		
		}
		return controller.getCurrentStatus();		
	}
	
	public GroupDispatcher(ProjectController controller, MediaStrategy mediaStrategy) {
		this.controller = controller;
		this.setMediaStrategy(mediaStrategy);
		
		this.controller.setGroupDispatcher(this);
		
		Timer timer = new Timer();
		timer.schedule(this, 0, 500);
	}
	
	
	
	
	
	@Override
	public void run() {
		if (elevatorControllers.size() > 0) {
			log.info("Sending Request Status Message to " + elevatorControllers.size() + " Elevator Controllers");
		}
		for (Byte key : elevatorControllers.keySet()) {
			ElevatorControllerConnection elevatorController = elevatorControllers.get(key);	
					
			elevatorController.sendMessage();
			
		}
		//controller.updateViews(getElevatorControllerStatuses());	
		
	}

	public byte addFloorRequest(FloorRequest floorRequest) {
		byte car = mediaStrategy.addFloorRequest(floorRequest);
		log.info("Floor Request added - " + floorRequest.toString());
		return car;
	}
	
	public void cancelFloorRequest(FloorRequest floorRequest) {
		synchronized (floorRequests) {
			
			
			if (!floorRequests.remove(floorRequest)) {
				log.error("Cannot remove a floor request that does not exist - " + floorRequest.toString() );
			} else {
				log.info("Floor Request cancelled - " + floorRequest.toString());
			}
		}
		
	}
	
	public HashMap<Byte, StatusMessage> getElevatorControllerStatuses() {
		HashMap<Byte, StatusMessage> statusMessages = new HashMap<Byte, StatusMessage>(CommonSettings.MAX_ELEVATOR_CONTROLLERS);
		for (Byte key : elevatorControllers.keySet()) {
			ElevatorControllerConnection elevatorController = elevatorControllers.get(key);			
			
			StatusMessage message = elevatorController.getCurrentStatus();
			if (message != null) {
				statusMessages.put(elevatorController.getCarNum(), message);
			}
			
			
		}
		
		return statusMessages;
	}
	
	public void addElevatorController(ElevatorControllerConnection elevatorController) {
		synchronized (elevatorControllers) {
			if (elevatorControllers.size() > CommonSettings.MAX_ELEVATOR_CONTROLLERS) {
				log.error("More than 8 elevator controllers have connected");
			}
			elevatorControllers.put(elevatorController.getCarNum(), elevatorController);
		}
		
		log.info("Client Thread was added - " + elevatorController.toString());
	}
	
	
	/**
	 * For use when a elevatorController is disconnected
	 * @param elevatorController
	 */
	public void removeElevatorController(ElevatorControllerConnection elevatorController) {
		synchronized (elevatorControllers) {
			elevatorControllers.remove(elevatorController.getCarNum());
		}
		log.info("Client Thread was removed - " + elevatorController.toString());
	}

	public MediaStrategy getMediaStrategy() {
		return mediaStrategy;
	}

	public void setMediaStrategy(MediaStrategy mediaStrategy) {
		this.mediaStrategy = mediaStrategy;
		this.mediaStrategy.setGroupDispatcher(this);
	}
}
